package com.lyy.lottery.service.mq;

import cn.hutool.core.date.DateUtil;
import com.lyy.lottery.common.exception.ServiceException;
import com.lyy.lottery.common.util.JacksonUtil;
import com.lyy.lottery.controller.param.DrawPrizeParam;
import com.lyy.lottery.dao.dataobject.ActivityPrizeDo;
import com.lyy.lottery.dao.dataobject.WinningRecordDO;
import com.lyy.lottery.dao.mapper.ActivityPrizeMapper;
import com.lyy.lottery.dao.mapper.WinningRecordMapper;
import com.lyy.lottery.service.DrawPrizeService;
import com.lyy.lottery.service.activitystatus.ActivityStatusManager;
import com.lyy.lottery.service.dto.ConvertActivityStatusDTO;
import com.lyy.lottery.service.enums.ActivityPrizeStatusEnum;
import com.lyy.lottery.service.enums.ActivityStatusEnum;
import com.lyy.lottery.service.enums.ActivityUserStatusEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.CollectionUtils;

import java.util.stream.Collectors;

import static com.lyy.lottery.common.config.DirectRabbitConfig.QUEUE_NAME;

@Component
@RabbitListener(queues = QUEUE_NAME)
@Slf4j
public class MqReceiver {

    @Autowired
    private DrawPrizeService drawPrizeService;
    @Autowired
    private ActivityStatusManager activityStatusManager;

    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    //@Autowired
    //private SMSUtil smsUtil;

    @Autowired
    private ActivityPrizeMapper activityPrizeMapper;
    @Autowired
    private WinningRecordMapper winningRecordMapper;

    @RabbitHandler
    public void process(Map<String,String> message) {
        //成功接收到队列中的消息
        log.info("mq成功接收到队列中的消息! message：{}",message);
        String paramString=message.get("messageData");
        DrawPrizeParam param= JacksonUtil.readValue(paramString,DrawPrizeParam.class);

        //处理抽奖流程
        try{
            //1、校验抽奖请求是否有效
            if (!drawPrizeService.checkDrawPrizeParam(param)){
                log.error("抽奖无效");
                return;
            }

            //2、状态扭转处理
            statusConvert(param);

            //3、保存中奖者名单
            List<WinningRecordDO> winningRecordDOList=drawPrizeService.saveWinnerRecords(param);

            //4、通知中奖者（邮箱 或 短信）
            syncExecute(winningRecordDOList);

        }catch (ServiceException e){
            log.error("处理MQ消息异常！{}:{}",e.getCode(),e.getMessage(),e);
            rollback(param);
            throw e;
        }catch (Exception e){
            log.error("处理MQ消息异常！",e);
            rollback(param);
            throw e;
        }

    }

    private void statusConvert(DrawPrizeParam param) {
        ConvertActivityStatusDTO convertActivityStatusDTO=new ConvertActivityStatusDTO();
        convertActivityStatusDTO.setActivityId(param.getActivityId());
        convertActivityStatusDTO.setPrizeId(param.getPrizeId());
        convertActivityStatusDTO.setUserIds(
                param.getWinnerList().stream().map(DrawPrizeParam.Winner::getUserId).collect(Collectors.toList())
        );
        convertActivityStatusDTO.setTargetActivityStatus(ActivityStatusEnum.COMPLETED);
        convertActivityStatusDTO.setTargetPrizeStatus(ActivityPrizeStatusEnum.COMPLETED);
        convertActivityStatusDTO.setTargetUserStatus(ActivityUserStatusEnum.COMPLETED);
        log.info("convertActivityStatusDTO :{}",convertActivityStatusDTO);

        activityStatusManager.handlerEvent(convertActivityStatusDTO);
    }

    //并发处理-异步处理
    private void syncExecute(List<WinningRecordDO> winningRecordDOList) {
        //通过线程池 threadPoolTaskExecutor
        //短信通知
        threadPoolTaskExecutor.execute(()->sendMessage(winningRecordDOList));
    }

    private void sendMessage(List<WinningRecordDO> winningRecordDOList) {
        if (CollectionUtils.isEmpty(winningRecordDOList)){
            log.info("中奖列表为空，不用发短信！");
            return;
        }
        log.info("中奖通知短息发送成功");
    }

    private void rollback(DrawPrizeParam param) {
        //1、回滚状态：活动、奖品、人员
        if (!statusNeedRollback(param)) return;
        rollbackStatus(param);

        //2、回滚中奖者名单
        if (!winnerNeedRollback(param)) return;
        rollbackWinner(param);
    }

    private boolean statusNeedRollback(DrawPrizeParam param) {
        //扭转状态时，为保证事务一致性，要么都扭转要么都不扭转
        //所以只需判断人员/奖品是否已扭转，即可判断出活动是否已扭转
        ActivityPrizeDo apDo=activityPrizeMapper.selectByAPId(param.getActivityId(),param.getPrizeId());
        return apDo.getStatus().equalsIgnoreCase(ActivityPrizeStatusEnum.COMPLETED.name());//已完成则表示已扭转--true--!true--需要回滚
    }

    private void rollbackStatus(DrawPrizeParam param) {
        ConvertActivityStatusDTO activityStatusDTO=new ConvertActivityStatusDTO();
        activityStatusDTO.setActivityId(param.getActivityId());
        activityStatusDTO.setPrizeId(param.getPrizeId());
        activityStatusDTO.setUserIds(param.getWinnerList().stream()
                .map(DrawPrizeParam.Winner::getUserId).collect(Collectors.toList()));
        activityStatusDTO.setTargetActivityStatus(ActivityStatusEnum.RUNNING);
        activityStatusDTO.setTargetPrizeStatus(ActivityPrizeStatusEnum.INIT);
        activityStatusDTO.setTargetUserStatus(ActivityUserStatusEnum.INIT);
        activityStatusManager.rollbackHandleEvent(activityStatusDTO);
    }

    private boolean winnerNeedRollback(DrawPrizeParam param) {
        //判断winning_record此活动是否存在中奖者
        int count=winningRecordMapper.countByAPId(param.getActivityId(),param.getPrizeId());
        return count>0;
    }

    private void rollbackWinner(DrawPrizeParam param) {
        drawPrizeService.deleteRecords(param.getActivityId(),param.getPrizeId());
    }
}

/*
    private void sendMessage(List<WinningRecordDO> winningRecordDOList) {
        if (CollectionUtils.isEmpty(winningRecordDOList)){
            log.info("中奖列表为空，不用发短信！");
            return;
        }
        log.info("中奖通知短息发送成功");
        for (WinningRecordDO wrDo :winningRecordDOList){
            Map<String,String> map=new HashMap<>();
            map.put("name",wrDo.getWinnerName());
            map.put("activityName",wrDo.getActivityName());
            map.put("prizeTiers",wrDo.getPrizeTier());
            map.put("prizeName", wrDo.getPrizeName());
            map.put("winningTime",DateUtil.formatTime(wrDo.getWinningTime()));
            smsUtil.sendMessage("SMS_480415129",wrDo.getWinnerPhoneNumber().getValue(),
                    JacksonUtil.writeValueAsString(map));
        }
    }

*/




















